
package com.xayq.orap.oauth.token;

import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import com.xayq.orap.model.ClientDetails;
import com.xayq.orap.model.User;
import com.xayq.orap.oauth.MyOAuthTokenRequest;
import com.xayq.orap.oauth.OAuthHandler;
import com.xayq.orap.utils.CommonUtils;

import javax.servlet.http.HttpServletResponse;

@Component
public abstract class AbstractOAuthTokenHandler extends OAuthHandler{

    private static final Logger LOG = LoggerFactory.getLogger(AbstractOAuthTokenHandler.class);


    protected MyOAuthTokenRequest tokenRequest;

    public void handle(MyOAuthTokenRequest tokenRequest, HttpServletResponse response) throws OAuthProblemException, OAuthSystemException {
        this.tokenRequest = tokenRequest;
        this.response = response;

        //validate
        if (checkValidateResponse(validate())) {            
        	return;
        }else{        	
        	handleAfterValidation();
        }       
    }
    
//    public OAuthResponse validate1() throws OAuthSystemException {
//    	ClientDetails clientDetails = clientDetails();
//		if (clientDetails == null) {
//			 return invalidClientErrorResponse();
//        }
//		return null;
//    }
    public OAuthResponse validateSelf() throws OAuthSystemException {
    	
    	//ClientDetails clientDetails = clientDetails();
    	
    	String grantType = tokenRequest.getGrantType();
        if (!clientDetails.getGrantTypes().contains(grantType)) {
            LOG.debug("Invalid grant_type '{}', client_id = '{}'", grantType, clientDetails.getClientId());
            return invalidGrantTypeResponse(grantType);
        }

        //validate client_secret
        String clientSecret = tokenRequest.getClientSecret();
        if (clientSecret == null || !clientSecret.equals(clientDetails.getClientSecret())) {
            LOG.debug("Invalid client_secret '{}', client_id = '{}'", clientSecret, clientDetails.getClientId());
            return invalidClientSecretResponse();
        }
        
        return validatePlus();
    }

    protected abstract OAuthResponse validatePlus() throws OAuthSystemException;
    

//    protected boolean checkValidateResponse(OAuthResponse oAuthResponse) {
//        if (oAuthResponse != null) {
//            LOG.debug("Validate OAuthAuthzRequest(client_id={}) failed", tokenRequest.getClientId());
//            CommonUtils.writeOAuthJsonResponse(response, oAuthResponse);
//            return true;
//        }
//        return false;
//    }
    
//    protected OAuthResponse invalidClientErrorResponse() throws OAuthSystemException {
//        return OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
//                .setError(OAuthError.TokenResponse.INVALID_CLIENT)
//                .setErrorDescription("Invalid client_id '" + tokenRequest.getClientId() + "'")
//                .buildJSONMessage();
//    }

//    protected OAuthResponse invalidRedirectUriResponse() throws OAuthSystemException {
//        return OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
//                .setError(OAuthError.CodeResponse.INVALID_REQUEST)
//                .setErrorDescription("Invalid redirect_uri '" + tokenRequest.getRedirectURI() + "'")
//                .buildJSONMessage();
//    }
//
//    protected OAuthResponse invalidScopeResponse() throws OAuthSystemException {
//        return OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
//                .setError(OAuthError.CodeResponse.INVALID_SCOPE)
//                .setErrorDescription("Invalid scope '" + tokenRequest.getScopes() + "'")
//                .buildJSONMessage();
//    }
//
//    protected OAuthResponse invalidClientSecretResponse() throws OAuthSystemException {
//        return OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
//                .setError(OAuthError.TokenResponse.UNAUTHORIZED_CLIENT)
//                .setErrorDescription("Invalid client_secret by client_id '" + tokenRequest.getClientId() + "'")
//                .buildJSONMessage();
//    }
//    
//    protected OAuthResponse invalidGrantTypeResponse(String grantType) throws OAuthSystemException {
//        return OAuthResponse.errorResponse(HttpServletResponse.SC_UNAUTHORIZED)
//                .setError(OAuthError.TokenResponse.INVALID_GRANT)
//                .setErrorDescription("Invalid grant_type '" + grantType + "'")
//                .buildJSONMessage();
//    }
//
//
//    //true is invalided
//    protected boolean invalidUsernamePassword() {
//        String username = tokenRequest.getUsername();
//        String password = tokenRequest.getPassword();
//        
//        User u = userMapper.loadUserByUsername(username);
//        try {
//			if(CommonUtils.getMD5(password+"{"+username+"}").equals(u.getPassword())){
//				return false;
//			}
//		} catch (NoSuchAlgorithmException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//        return true;    
//    }
//
//    protected OAuthResponse invalidUsernamePasswordResponse() throws OAuthSystemException {
//        return OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
//                .setError(OAuthError.TokenResponse.INVALID_GRANT)
//                .setErrorDescription("Bad credentials")
//                .buildJSONMessage();
//    }
//    
//	protected boolean excludeScopes(Set<String> scopes, ClientDetails clientDetails) {
//        Map<String, Set<String>> allowedScope = new HashMap<String, Set<String>>();
//    	String clientScopes = clientDetails.getScope();
//        for(String clientScope:clientScopes.split(";")){
//        	Set<String> value = new HashSet<String>();
//        	if(clientScope.split("@").length > 1){
//        		CollectionUtils.addAll(value,clientScope.split("@")[1].split(","));
//        	}
//        	allowedScope.put(clientScope.split("@")[0],value);
//        }
//
//        for (String scope : scopes) {
//        	String scopeKey = scope.split("@")[0];
//        	Set<String> scopeValue = new HashSet<String>();
//        	if(scope.split("@").length > 1){
//        		CollectionUtils.addAll(scopeValue,scope.split("@")[1].split(","));
//        	}
//        	if(allowedScope.containsKey(scopeKey)&&
//        			((scopeValue.isEmpty()&&allowedScope.get(scopeKey).isEmpty())||
//        			((!scopeValue.isEmpty())&&allowedScope.get(scopeKey).containsAll(scopeValue)))
//        	){
//        		
//        	}else{
//                LOG.debug("Invalid scope - ClientDetails scopes '{}' exclude '{}'", clientScopes, scope);
//                return true;
//            }
//        }
//        return false;
//    }
    @Override
    protected String getClientId() {
        return tokenRequest.getClientId();
    }
    @Override
    protected String getRedirectURI() {
        return tokenRequest.getRedirectURI();
    }
    @Override
    protected Set<String> getScopes() {
        return tokenRequest.getScopes();
    }


    protected abstract void handleAfterValidation() throws OAuthProblemException, OAuthSystemException;
    

}
